package com.softaria.windows.view;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.http.client.URL;
import com.softaria.windows.logic.HelpWriter;
import com.softaria.windows.model.View;
import com.softaria.windows.model.ViewUrl;
import com.softaria.windows.widgets.FrameResizeListenerRegistrator;

/**
 * Deafult view factory is just default (or proof of concept, if you want)
 * version of {@link ViewFactory}.
 * 
 * ViewFactory is simple interface for converting ViewUrls to actual Views.
 * There is exactly one view factory for whole system. So, it must be
 * responsible for creating all kind of views.
 * 
 * DefaultViewFactory addresses the common case when you have several types of
 * views. So it has 2 steps algorithm. On first step it determines the type of
 * view to be created via calling abstract (overridden by user) method
 * getViewType. This method is provided with ViewUrl and can do anything it
 * wants to determine view type. Second step is forwarding request to
 * {@link TypedViewFactory}, which was registered for serving views of the given
 * type.
 * 
 * 
 * @author Roman M Kuzmin (roman@softaria.com)
 * 
 */
public abstract class DefaultViewFactory implements ViewFactory {

  private HashMap<String, TypedViewFactory> typedFactories = new HashMap<String, TypedViewFactory>();

  public View createView(ViewUrl url, ViewCloseListenerRegistrator closeListenerRegistrator,
      FrameResizeListenerRegistrator frlr, HelpWriter helpWriter) throws BadViewUrlException {

    Map<String, List<String>> params = parseParameters(url.getParameters());

    String viewType = getViewType(url.getViewId(), params);

    TypedViewFactory tvFactory = typedFactories.get(viewType);

    if (tvFactory == null) {
      throw new BadViewUrlException();
    }

    View view = tvFactory.createView(params, closeListenerRegistrator, frlr, helpWriter);

    view.setViewUrl(url);

    return view;
  }

  protected abstract String getViewType(String viewId, Map<String, List<String>> params);

  private static Map<String, List<String>> parseParameters(String qs) {
    if (qs == null)
      return null;

    qs = qs.trim();
    if (qs.length() == 0)
      return null;

    Map<String, List<String>> out = new HashMap<String, List<String>>();

    for (String kvPair : qs.split("&")) {
      String[] kv = kvPair.split("=", 2);
      if (kv[0].length() == 0) {
        continue;
      }

      List<String> values = out.get(kv[0]);
      if (values == null) {
        values = new ArrayList<String>();
        out.put(kv[0], values);
      }

      values.add(kv.length > 1 ? URL.decode(kv[1]) : "");
    }

    return out;

  }

  public void registerTypedViewFactory(String viewType, TypedViewFactory factory) {
    if (typedFactories.containsKey(viewType)) {
      throw new IllegalArgumentException("Key " + viewType + " is already in use");
    }

    typedFactories.put(viewType, factory);
  }
}
